'use strict';

const path = require('path');

const Conf = require('conf');
const fsExtra = require('fs-extra');
const colors = require('colors');

const Command = require('@x3-cli-dev/command');
const log = require('@x3-cli-dev/log');
const { execCommandAsync, WORKSPACE_PROXY_CONFIG_NAME } = require('@x3-cli-dev/utils');
const { startServer } = require('./server');

class ProxyCommand extends Command {
  init() {
    this.list = this._options.list;
    this.edit = !!this._options.edit;
    this.use = this._options.use;
    this.port = this._options.port;
    const exclude = ['port'];
    this.optionKeys = Object.keys(this._options).filter(key => !exclude.includes(key));
    log.verbose('list', this.list);
    log.verbose('edit', this.edit);
    log.verbose('use', this.use);
    log.verbose('port', this.port);
    log.verbose('options', this._options);
    log.verbose('optionKeys', this.optionKeys);
  }

  async exec() {
    try {
      await this.prepare();
      await this.execOptionsFn();
    } catch (error) {
      log.error(error.message);
      if (this.isDebug) {
        console.log(error);
      }
      process.exit(0);
    } finally {
      // process.exit(0);
    }
  }

  async prepare() {
    await this.checkConf();
  }

  async checkConf() {
    let cliPath = process.env.X3_CLI_HOME_PATH;
    let configName = 'proxy';
    // 是否使用本地工作空间配置
    if (fsExtra.pathExistsSync(path.join(process.cwd(), WORKSPACE_PROXY_CONFIG_NAME))) {
      cliPath = path.join(process.cwd());
      configName = '.x3proxy'
    }
    const config = new Conf({
      cwd: cliPath,
      configName,
    });
    this.proxyCommon = config.get('common');
    this.proxyObj = config.get('proxy');
    log.verbose('proxyCommon', this.proxyCommon);
    log.verbose('proxyObj', this.proxyObj);
  }

  async execOptionsFn() {
    const fnMap = {
      edit: this.editFn,
      list: this.listFn,
      use: this.useFn,
    };
    for (const key of this.optionKeys) {
      await fnMap[key].call(this);
    }
  }

  async useFn() {
    let proxy = this.proxyObj[this.use];
    if (proxy) {
      proxy = this.normalizedParameter(this.use);
      log.verbose('proxy', proxy);
      await startServer(proxy);
    } else {
      throw new Error(`找不到代理配置 ${this.use}, 可能的配置\n${colors.yellow(Object.keys(this.proxyObj))}`);
    }
  }

  async listFn() {
    let output = {};
    if (this.proxyObj[this.list]) {
      output = this.proxyObj[this.list];
    } else {
      output = Object.keys(this.proxyObj)
        .map(key => this.proxyObj[key])
        .flat(1);
    }
    console.table(output, ['name', 'target', 'userName', 'password']);
  }

  async editFn() {
    const proxyFilePath = this.getProxyFilePath();
    await execCommandAsync(`vim ${proxyFilePath}`);
  }

  getProxyFilePath() {
    const cliPath = process.env.X3_CLI_HOME_PATH;
    const proxyFilePath = path.join(cliPath, 'proxy.json');
    return proxyFilePath;
  }

  normalizedParameter(proxyName) {
    return {
      ...this.proxyObj[proxyName][0],
      ...this.proxyCommon,
      port: this.port ?? this.proxyCommon.port,
      loginApi: this.proxyObj[proxyName][0]?.loginApi ?? this.proxyCommon.loginApi,
    };
  }
}

function proxy(argv) {
  return new ProxyCommand(argv);
}

module.exports = proxy;
module.exports.ProxyCommand = ProxyCommand;
